﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.IO;
using System.Data;
using CSNN.GUI;
using Microsoft.Win32;

namespace CSNN
{
    /// <summary>
    /// Логика взаимодействия для WindowTrainingImages.xaml
    /// </summary>
    public partial class WindowTrainingImages : Window
    {
        private BindingList<TrainingImageInList> _TrainingImageList;
        private VoidDelegat UpdateMainWindow;
        private int _inDemension, _outDemension;
        
        /// <summary>
        /// Список входов
        /// </summary>
        private BindingList<NewImage> _Inputs;

        /// <summary>
        /// Список выходов
        /// </summary>
        private BindingList<NewImage> _Outputs;
        
        
        public WindowTrainingImages()
        {
            InitializeComponent();

            _Inputs = new BindingList<NewImage>();
            _Outputs = new BindingList<NewImage>();
        }

        /// <summary>
        /// Установка значений размерности входных и выходных сигналов обучающих образов, а так же привязка и отображение данных
        /// </summary>
        /// <param name="InDemension">Размерность входных образов</param>
        /// <param name="OutDemension">Размерность выходных образов</param>
        /// <param name="TrainigImageList">Объект коллекции обучающих образов</param>
        /// <param name="dl">Делегат функции обновления главного окна</param>
        public void SetImagesDemension(int InDemension, int OutDemension, BindingList<TrainingImageInList> TrainigImageList, VoidDelegat dl)
        {
            if (InDemension <= 0 || OutDemension <= 0 || TrainigImageList == null)
            {
                throw new ArgumentException("Ошибка! Переданы не корректные аргументы!");
            }

            UpdateMainWindow = dl;

            this._inDemension = InDemension;
            this._outDemension = OutDemension;
            this._TrainingImageList = TrainigImageList;

            _Inputs.Add(new NewImage(1,"0"));
            for (int i = 1; i < _inDemension; i++)
            {
                _Inputs.Add(new NewImage(0,i.ToString()));
            }
            for (int i = 0; i < _outDemension; i++)
            {
                _Outputs.Add(new NewImage(0,i.ToString()));
            }

            this.dataGridInputs.ItemsSource = _Inputs;
            this.dataGridInputs.IsReadOnly = false;

            this.DataGridOutputs.ItemsSource = _Outputs;
            this.DataGridOutputs.IsReadOnly = false;
            
            GridShowAllImages.ItemsSource = _TrainingImageList;
            GridShowAllImages.IsReadOnly = false;

        }

        // Добавление обучающего образа в коллекцию
        private void button2_Click(object sender, RoutedEventArgs e)
        {
            double[] inPuts = new double[_inDemension];
            double[] outPuts = new double[_outDemension];

            for (int i = 0; i < _inDemension; i++)
            {
                inPuts[i] = _Inputs[i].Unit;
            }
            for (int i = 0; i < _outDemension; i++)
            {
                outPuts[i] = _Outputs[i].Unit;
            }

            TrainingImageInList image = new TrainingImageInList(_inDemension, _outDemension, _TrainingImageList.Count, "");
            image.SetTrainingImage(inPuts, outPuts);

            _TrainingImageList.Add(image);
        }


        #region Запись/Чтение образов из файла

        /// <summary>
        /// Чтение обучающих образов из CSV-файла
        /// </summary>
        /// <param name="filePath">Путь к файлу</param>
        private void LoadFromCSV(string filePath)
        {
            StreamReader loadStream;

            try
            {
                loadStream = new StreamReader(filePath);
            }
            catch
            {
                throw;
            }
            
            string[] values;
            string inputLine;

            // Чтение размерности образов (первая строка файла)
            if ((inputLine = loadStream.ReadLine()) != null)
            {
                values = inputLine.Split(';');
            }
            else
            {
                throw new FileLoadException("Ошибка! Файл пуст.");
            }

            if ((Int32.Parse(values[0]) != _inDemension) || (Int32.Parse(values[1]) != _outDemension))
                throw new InvalidDataException("Размерность образов не соответсвует размерности текущей нейронной сети");

            double[] imageIn = new double[_inDemension];
            double[] imageOut = new double[_outDemension];
            
            string imageDiscription;

            // Чтение образов
            while ((inputLine = loadStream.ReadLine()) != null)
            {
                values = inputLine.Split(';');

                if (inputLine == "") continue;

                if (values.Length != _inDemension + _outDemension + 1)
                    throw new InvalidDataException("Ошибка! Размерность "+_TrainingImageList.Count.ToString() + " образа в загружаемом файле не соответсвует размерности текущей нейронной сети.");

                for (int i = 0; i < _inDemension; i++)
                    imageIn[i] = Double.Parse(values[i]);
                for (int i = 0; i < _outDemension; i++)
                    imageOut[i] = Double.Parse(values[i + _inDemension]);

                imageDiscription = values[values.Length - 1];

                _TrainingImageList.Add(new TrainingImageInList(_inDemension,_outDemension,_TrainingImageList.Count,imageDiscription));
                _TrainingImageList[_TrainingImageList.Count - 1].SetTrainingImage(imageIn, imageOut);
            }

            loadStream.Close();
            
        }

        /// <summary>
        /// Запись обучающих множеств в CSV-файл
        /// </summary>
        /// <param name="filePath">Путь к файлу</param>
        private void SaveToCSV(string filePath)
        {
            if (filePath == null)
            {
                MessageBox.Show("Не удалось сохранить в файл!", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);    
            }

            using (StreamWriter writeStream = new StreamWriter(filePath))
            {
                writeStream.WriteLine("{0:d};{1:d}",_inDemension,_outDemension);
                writeStream.WriteLine("");
                foreach (TrainingImageInList trImage in _TrainingImageList)
                {
                    for (int i = 0; i < _inDemension; i++)
                        writeStream.Write(trImage.GetInSignal(i).ToString() + ";");
                    for (int i = 0; i < _outDemension; i++)
                        writeStream.Write(trImage.GetOutSignal(i).ToString() + ";");
                    writeStream.WriteLine(trImage.Discription);
                }
            }
        }

        #endregion

        /// <summary>
        /// Загрузка образов кнопкой "Загрузить образы"
        /// </summary>
        private void buttonLoadImages_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openDialog = new OpenFileDialog();
            openDialog.Filter = "CSV (*.csv)|*.csv";
            openDialog.CheckFileExists = true;
            openDialog.Multiselect = false;
            if (openDialog.ShowDialog() == true)
                LoadFromCSV(openDialog.FileName);
        }

        /// <summary>
        /// Сохранение образов кнопкой "Сохранить образы"
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonSaveImages_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog saveDialog = new SaveFileDialog();
            saveDialog.Filter = "CSV (*.csv)|*.csv";
            saveDialog.OverwritePrompt = true;
            saveDialog.AddExtension = true;
            if (saveDialog.ShowDialog() == true)
                SaveToCSV(saveDialog.FileName);    
        }


        public void DestructInfo()
        {
            this._TrainingImageList = null;
            this.UpdateMainWindow = null;
            this._inDemension = 0;
            this._outDemension = 0;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {

        }

        private void Window_Closed(object sender, CancelEventArgs e)
        {
            UpdateMainWindow();
            DestructInfo();
        }

        public void Close_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
    }
}
